﻿#region Copyright RenGuiYou. All rights reserved.
//=====================================================
// PandoraFrameWork
// Author:      RenGuiyou
// Feedback: 	mailto:750539605@qq.com
//=====================================================
#endregion
using System;
using System.Collections.Generic;
using UnityEngine;
using Object = UnityEngine.Object;

namespace Pandora.Console
{
    [DisallowMultipleComponent]
    public class PdrConsoleWindow : MonoBehaviour
    {
        #region 适配
        //缩小窗口
        public static Rect DefaultIconRect;
        //展开窗口
        public static readonly Rect DefaultWindowRect = new Rect(0, 0, Screen.width, Screen.height);
        //缩放比
        public static readonly float DefaultWindowScale = 1f;
        public static Vector2 ButtonSize = new Vector2(100, 50);
        public static Vector2 ToggleSize = new Vector2(90, 40);
        public static int spaceHeight = 5;
        public static GUIStyle labelStyle;
        public static GUIStyle buttonStyle;
        public static GUIStyle toggleStyle;
        public static GUIStyle windowStyle;
        [SerializeField] private bool m_ShowFullWindow;
        private IConsoleManager _mConsoleManager;
        private Rect m_DragRect = new Rect(0f, 0f, float.MaxValue, 25f);
        private Rect m_IconRect;
        private Rect m_WindowRect = DefaultWindowRect;
        #endregion
        #region Window对象
        [SerializeField] private LogWindow _mLogWindow = new LogWindow();
        private SystemInfoWindow m_SystemInfoWindow = new SystemInfoWindow();
        private GraphicsInfoWindow m_GraphicsInfoWindow = new GraphicsInfoWindow();
        private ScreenInfoWindow m_ScreenInfoWindow = new ScreenInfoWindow();
        private ProfilerInfoWindow m_ProfilerInfoWindow = new ProfilerInfoWindow();
        private RunTimeMemoryWindow<Object> m_AllMemoryWindow = new RunTimeMemoryWindow<Object>();
        private RunTimeMemoryWindow<Texture> m_TextureMemoryWindow = new RunTimeMemoryWindow<Texture>();
        private RunTimeMemoryWindow<Mesh> m_MeshMemoryWindow = new RunTimeMemoryWindow<Mesh>();
        private RunTimeMemoryWindow<Material> m_MaterialMemoryWindow = new RunTimeMemoryWindow<Material>();
        private RunTimeMemoryWindow<AnimationClip> m_AnimationClipMemoryWindow = new RunTimeMemoryWindow<AnimationClip>();
        private RunTimeMemoryWindow<AudioClip> m_AudioClipMemoryWindow = new RunTimeMemoryWindow<AudioClip>();
        private RunTimeMemoryWindow<Font> m_FontMemoryWindow = new RunTimeMemoryWindow<Font>();
        private RunTimeMemoryWindow<GameObject> m_GameObjectMemoryWindow = new RunTimeMemoryWindow<GameObject>();
        private RunTimeMemoryWindow<Component> m_ComponentMemoryWindow = new RunTimeMemoryWindow<Component>();
        #endregion
        #region Property
        public float UpdateInterval = 0.5f;
        float m_lastInterval;
        int m_fps;
        int m_frames;
        public static bool ShowLuaMemory;
        public static int luaMemorySize;
        public static int luaMemoryDelta;
        private int m_luaMemoryLast;
        #endregion

        public void Start()
        {
            _mConsoleManager = new ConsoleManager();
            RegisterAllWindows();
        }

        public virtual void RegisterAllWindows()
        {
            RegisterNDebugWindow("控制台", _mLogWindow);
            RegisterNDebugWindow("内存分析/Profiler", m_ProfilerInfoWindow);
            RegisterNDebugWindow("内存分析/内存/All", m_AllMemoryWindow);
            RegisterNDebugWindow("内存分析/内存/贴图", m_TextureMemoryWindow);
            RegisterNDebugWindow("内存分析/内存/GO", m_GameObjectMemoryWindow);
            RegisterNDebugWindow("内存分析/内存/脚本", m_ComponentMemoryWindow);
            RegisterNDebugWindow("内存分析/内存/网格", m_MeshMemoryWindow);
            RegisterNDebugWindow("内存分析/内存/材质", m_MaterialMemoryWindow);
            RegisterNDebugWindow("内存分析/内存/动画", m_AnimationClipMemoryWindow);
            RegisterNDebugWindow("内存分析/内存/音效", m_AudioClipMemoryWindow);
            RegisterNDebugWindow("内存分析/内存/字体", m_FontMemoryWindow);
            RegisterNDebugWindow("设备信息/系统信息", m_SystemInfoWindow);
            RegisterNDebugWindow("设备信息/显卡信息", m_GraphicsInfoWindow);
            RegisterNDebugWindow("设备信息/屏幕信息", m_ScreenInfoWindow);
            RegisterNDebugWindow("资源分析/加载性能/从Bundle加载Asset", new AssetLoadWindow());
            RegisterNDebugWindow("资源分析/加载性能/加载AssetBundle", new BundleLoadWindow());
            RegisterNDebugWindow("资源分析/资源池/AssetBundle", new BundlePoolWindow());
            RegisterNDebugWindow("资源分析/资源池/图集", new AtlasPoolWindow());
        }

        public void RegisterNDebugWindow(string path, IConsoleWindow consoleWindow, params object[] args)
        {
            _mConsoleManager.RegisterConsoleWindow(path, consoleWindow, args);
        }

        public void OnGUI()
        {
            InitShow();
            if (m_ShowFullWindow)
            {
                m_WindowRect = GUILayout.Window(0, m_WindowRect, DrawWindow, "<b>Pandora Console</b>", windowStyle);
            }
            else
            {
                m_IconRect = GUILayout.Window(0, m_IconRect, DrawNDebugWindowIcon, "<b>Pandora</b>", windowStyle);
            }
        }

        void InitShow()
        {
            if (buttonStyle != null) return;
            int commonFontSize = 15;
            spaceHeight = 5;
            buttonStyle = GUI.skin.button;
            toggleStyle = GUI.skin.toggle;
            windowStyle = GUI.skin.window;
            labelStyle = GUI.skin.label;
            if (Screen.width > 768)
            {
                DefaultIconRect = new Rect(10, Screen.height / 2.0f, 120, 120);
                ButtonSize = ButtonSize * 2;
                ToggleSize = ToggleSize * 2;
                windowStyle.border.top = 12;
                windowStyle.padding.top = 30;
                commonFontSize = 30;
                spaceHeight = 15;
                toggleStyle.padding.top = 10;
                toggleStyle.border.top = 12;
                toggleStyle.border.left = 14;
                toggleStyle.border.top = 0;
                toggleStyle.padding.left = 15;
                ScrollWindowBase.TitleWidth = 340;
            }
            else if (Screen.width > 640)
            {
                DefaultIconRect = new Rect(10, Screen.height / 2.0f, 100, 80);
                spaceHeight = 10;
            }
            else
            {
                DefaultIconRect = new Rect(10, Screen.height / 2.0f, 60, 60);
            }
            buttonStyle.fixedHeight = ButtonSize.y;
            windowStyle.fontSize = commonFontSize;
            buttonStyle.fontSize = commonFontSize;
            toggleStyle.fontSize = commonFontSize;
            labelStyle.fontSize = commonFontSize;
            toggleStyle.alignment = TextAnchor.MiddleCenter;
            m_IconRect = DefaultIconRect;
        }

        private void DrawWindow(int windowId)
        {
            GUI.DragWindow(m_DragRect);
            DrawNDebugWindowGroup(_mConsoleManager.ConsoleWindowRoot);
        }

        private void DrawNDebugWindowGroup(IConsoleWindowGroup consoleWindowGroup)
        {
            if (consoleWindowGroup == null)
            {
                return;
            }
            GUILayout.Space(spaceHeight);
            List<string> names = new List<string>();
            string[] NDebugWindowNames = consoleWindowGroup.GetWindowNames();
            for (int i = 0; i < NDebugWindowNames.Length; i++)
            {
                names.Add(string.Format("<b>{0}</b>", NDebugWindowNames[i]));
            }
            if (consoleWindowGroup == _mConsoleManager.ConsoleWindowRoot)
            {
                names.Add("<b>Close</b>");
            }
            int toolbarIndex = GUILayout.Toolbar(consoleWindowGroup.SelectedIndex, names.ToArray(), buttonStyle, GUILayout.Height(ButtonSize.y),
                GUILayout.MaxWidth(Screen.width));
            if (toolbarIndex >= consoleWindowGroup.WindowCount)
            {
                m_ShowFullWindow = false;
                return;
            }
            if (consoleWindowGroup.SelectedIndex != toolbarIndex)
            {
                consoleWindowGroup.SelectedWindow.OnLeave();
                consoleWindowGroup.SelectedIndex = toolbarIndex;
                consoleWindowGroup.SelectedWindow.OnEnter();
            }
            IConsoleWindowGroup subConsoleWindowGroup = consoleWindowGroup.SelectedWindow as IConsoleWindowGroup;
            if (subConsoleWindowGroup != null)
            {
                DrawNDebugWindowGroup(subConsoleWindowGroup);
            }
            if (consoleWindowGroup.SelectedWindow != null)
            {
                GUILayout.Space(spaceHeight);
                consoleWindowGroup.SelectedWindow.OnDraw();
            }
        }

        private void DrawNDebugWindowIcon(int windowId)
        {
            GUILayout.Space(spaceHeight * 2);
            GUI.DragWindow(m_DragRect);
            Color32 color;
            _mLogWindow.RefreshCount();
            if (_mLogWindow.FatalCount > 0)
            {
                color = _mLogWindow.GetLogStringColor(LogType.Exception);
            }
            else if (_mLogWindow.ErrorCount > 0)
            {
                color = _mLogWindow.GetLogStringColor(LogType.Error);
            }
            else if (_mLogWindow.WarningCount > 0)
            {
                color = _mLogWindow.GetLogStringColor(LogType.Warning);
            }
            else
            {
                color = _mLogWindow.GetLogStringColor(LogType.Log);
            }
            string title = string.Format("<color=#{0:x2}{1:x2}{2:x2}{3}><b>FPS: {4}</b></color>", color.r, color.g, color.b, color.a.ToString("x2"), m_fps);
            if (GUILayout.Button(title, buttonStyle, GUILayout.Width(ButtonSize.x), GUILayout.Height(ButtonSize.y)))
            {
                m_ShowFullWindow = true;
            }
        }

        public void Update()
        {
            ++m_frames;
            float timeNow = Time.realtimeSinceStartup;
            OnPreUpdate();
            if (timeNow > m_lastInterval + UpdateInterval)
            {
                luaMemoryDelta = luaMemorySize - m_luaMemoryLast;
                m_luaMemoryLast = luaMemorySize;
                m_fps = (int)(m_frames / (timeNow - m_lastInterval));
                m_frames = 0;
                m_lastInterval = timeNow;
            }
        }

        public virtual void OnPreUpdate()
        {
        }
    }
}